/**
 *******************************************************************************
 * @FileName  : spp_main.c
 * @Author    : GaoQiu
 * @CreateDate: 2020-05-18
 * @Copyright : Copyright(C) GaoQiu
 *              All Rights Reserved.
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * GaoQiu and is available under the terms of Commercial License Agreement
 * between GaoQiu and the licensee in separate contract or the terms described
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */
#include "spp_main.h"
#include "utils/track.h"
#include "utils/assert.h"
#include "utils/utils.h"

#include "component/kv/kv_api.h"

#include "bsp/bsp.h"

SPPCb_t SppCb;


void SPP_MsgHandler(MdcEventMask_t event, MdcMsgHdr_t *pMsg)
{
	/* Message Handle */
	if(pMsg)
	{

	}

	/* Event Handle */
	if(event)
	{

	}
}


void SPP_Init(uint8_t *pBuf, uint32_t bufSize)
{
	if(SppCb.initialized)
		return;

	SppCb.handlerId = MDC_AddMsgHandler(SPP_MsgHandler);

	SppCb.pRxBuf = pBuf;
	SppCb.rxBufSize = bufSize;
	SppCb.rxCnt  = 0;
	SppCb.plyLen = 0;
	SppCb.state  = SPP_STATE_RX_HDR;

	MdcMsgHdr_t msg;
	msg.event = 0x0001;
	msg.param = 0;
	MDC_TimerConfig(&SppCb.timeoutTimer, SppCb.handlerId, &msg);

	SppCb.initialized = true;
}


void SPP_ResetState(void)
{
	SppCb.plyLen = 0;
	SppCb.rxCnt = 0;
	SppCb.state = SPP_STATE_RX_HDR;
}

void SPP_SwitchStateTo(uint8_t state)
{
	SppCb.state = state;
}

bool_t SPP_IsValidType(uint8_t type)
{
	return (type <= SPP_CMD_TYPE_DFU) ? true:false;
}

bool_t SPP_IsValidOpcode(uint8_t type, uint8_t opcode)
{
	if(type == SPP_CMD_TYPE_CFG){
		if(opcode <= SPP_CFG_OPCODE_MAX){
			return true;
		}
	}
	else if(type == SPP_CMD_TYPE_BLE){
		if(opcode <= SPP_BLE_OPCODE_MAX){
			return true;
		}
	}
	else if(type == SPP_CMD_TYPE_CFG){
		return false; //TODO:
	}
	return false;
}

void SPP_ConfigCmdHandler(SppFrame_t *pFrame)
{
	switch(pFrame->opcode)
	{
	case SPP_CFG_OPCODE_SET_MAC_ADDR:
	{
		TRACK_WRN("Set MAC Address:");
		TRACK_DATA(pFrame->data, pFrame->pldLen);

		int res = kv_set_item(GetConfigName(CFG_MAC_ADDR_IDX), pFrame->data, 6);
		if(res != KV_OK){
			TRACK_ERR("set mac address failed\n");
		}

		TRACK_WRN("Reset MCU...\r\n");
		PWR_McuReboot();
		break;
	}
	case SPP_CFG_OPCODE_GET_MAC_ADDR:
	{
		uint8_t addr[6] = {0};

		uint32_t len = kv_get_item_ex(GetConfigName(CFG_MAC_ADDR_IDX), addr, 6);
		if(len == 0){
			TRACK_ERR("Have no MAC Address\n");
			break;
		}

		TRACK_WRN("Get MAC Address:");
		TRACK_DATA(addr, 6);
		break;
	}
	case SPP_CFG_OPCODE_SET_FILTER_MAC:
	{
		TRACK_WRN("Set Filter MAC Address:");
		TRACK_DATA(pFrame->data, pFrame->pldLen);

		uint8_t filtMac[8] = {0};
		filtMac[0] = pFrame->data[0];
		filtMac[1] = pFrame->data[1];
		memcpy(filtMac+2, pFrame->data + 2, 6);

		int res = kv_set_item(GetConfigName(CFG_MAC_FILTER_IDX), filtMac, sizeof(filtMac));
		if(res != KV_OK){
			break;
		}

		TRACK_WRN("Reset MCU...\r\n");
		PWR_McuReboot();
		break;
	}
	case SPP_CFG_OPCODE_GET_FILTER_MAC:
	{
		uint8_t filtMac[8] = {0};

		uint32_t len = kv_get_item_ex(GetConfigName(CFG_MAC_FILTER_IDX), filtMac, 8);
		if(len == 0){
			TRACK_ERR("Have no Filter MAC Address\n");
			break;
		}

		TRACK_WRN("Get Filter MAC Address:");
		TRACK_DATA(filtMac, 8);
		break;
	}
	case SPP_CFG_OPCODE_CLR_FILTER_MAC:
	{
		kv_del_item(GetConfigName(CFG_MAC_FILTER_IDX));

		TRACK_WRN("Clear Filter MAC Address Ok...\r\n");

		TRACK_WRN("Reset MCU...\r\n");
		PWR_McuReboot();
		break;
	}
	default:
		break;
	}
}

void SPP_ProtocolHandler(uint8_t *pPkt, uint32_t len)
{
	SppFrame_t *pFrame = (SppFrame_t*)pPkt;

	switch(pFrame->type)
	{
	case SPP_CMD_TYPE_CFG:
	{
		SPP_ConfigCmdHandler(pFrame);
		break;
	}
	case SPP_CMD_TYPE_BLE:
		break;

	default:
		break;
	}
}

void SPP_RxDataHandler(uint8_t data)
{
	SppFrame_t *pFrame = (SppFrame_t*)SppCb.pRxBuf;
	uint8_t *pRxBuf = SppCb.pRxBuf;

	switch(SppCb.state)
	{
	case SPP_STATE_RX_HDR:
	{
		pRxBuf[SppCb.rxCnt++] = data;

		if(!SPP_IsValidType(pFrame->type)){
			SPP_ResetState();
			break;
		}

		if(SppCb.rxCnt == 2){
			if(!SPP_IsValidOpcode(pFrame->type, pFrame->opcode)){
				SPP_ResetState();
				break;
			}
		}

		if(SppCb.rxCnt == SPP_HDR_LEN)
		{
			if(pFrame->pldLen == 0){
				SPP_ProtocolHandler(pRxBuf, SppCb.rxCnt);
				SPP_ResetState();
				break;
			}

			if(pFrame->pldLen + SPP_HDR_LEN > SppCb.rxBufSize){
				ASSERT(0, 0xEEEE0000);
			}

			SppCb.plyLen = 0;
			SPP_SwitchStateTo(SPP_STATE_RX_PAYLOAD);
		}
		break;
	}
	case SPP_STATE_RX_PAYLOAD:
	{
		pRxBuf[SppCb.rxCnt++] = data;
		SppCb.plyLen++;

		if(SppCb.plyLen == pFrame->pldLen){
			SPP_ProtocolHandler(pRxBuf, SppCb.rxCnt);
			SPP_ResetState();
		}
		break;
	}
	default:
		break;
	}
}








